class PSAIControllerBase extends UDKBot;

var PSPawnDidrik Target;
var float TimeSinceTargetLost;
var float TimeSinceTookCover;
var float TimeSinceUpset;
var float TimeSinceDeath;
var Vector LastKnownLocation;
var Vector TempDest;
var NavigationPoint CurrentNode;
var NavigationPoint NextNode;
var int NextPatrolNodeIndex;
var Vector PreviousLocation;
var Vector SpawnLocation;
var Vector SpawnFocalPoint;
var Rotator SpawnRotation;
var float TimeToDestroyDead;
var bool bFiring;
var bool bWaitingToFire;
var bool bReloading;
var bool bCheckDeadComrade;
var int MaxNodeCandidates;

var() array<NavigationPoint> PatrolNodes;

var bool bCanPlayAudio;

var Vector TraceStartLoc, TraceEndLoc;
var Rotator TraceStartRot, TraceEndRot;

var bool AI_DEBUG_ENABLED;


event Possess(Pawn inPawn, bool bVehicleTransition)
{
	super.Possess(inPawn, bVehicleTransition);
	SpawnLocation = Pawn.Location;
	SpawnRotation = Rotation;
	SpawnFocalPoint = SpawnLocation + Normal(Vector(SpawnRotation)) * 1000;
	Pawn.SetMovementPhysics();	

	// If the enemy is a patroller set the starting node
	if(PatrolNodes.Length > 0)
	{
		NextPatrolNodeIndex = 0;
	}
}

// Enemy is touched by another enemy
function BlockedByComrade()
{
	if(IsInState('Evade') ||
		IsInState('TakeCover'))
	{
		// Stop moving
		StopLatentExecution();
		Pawn.Acceleration = vect(0,0,0);

		// Find a new way
		if(WantToCover())
		{
			GotoState('TakeCover');
		}
		else
		{
			GotoState('Evade');
		}
	}
}

// Enemy is touched by the player
function TouchedByPlayer(Vector HitNormal)
{
	if(IsInState('Idle') ||
		IsInState('Hacking') ||
		IsInState('Patrol') ||
		IsInState('Upset') ||
		IsInState('Check') ||
		IsInState('GoToCheck') ||
		IsInState('BackToStart') )
	{
		// Stop moving
		StopLatentExecution();
		Pawn.Acceleration = vect(0,0,0);

		if(PSPawnEnemyRandom(Pawn).bChatting)
		{
			TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
			PSPawnEnemyRandom(Pawn).bChatting = false;
		}

		bCheckDeadComrade = false;
		Focus = none;
		SetRotation(Rotator(HitNormal));
		SetFocalPoint(Pawn.Location + Normal(HitNormal) * 1000);

		TimeSinceTargetLost = 0.0; // Tick() function in Check state is sometimes executed before Begin, so this is a work around
		LastKnownLocation = GetALocalPlayerController().Pawn.Location;
		GotoState('Check');
	}
}

function HeardSound(Vector NoiseSource)
{
	// Stop moving
	StopLatentExecution();
	Pawn.Acceleration = vect(0,0,0);

	Focus = none;
	SetRotation(Rotator(NoiseSource - Pawn.Location));
	SetFocalPoint(Pawn.Location + Normal(NoiseSource - Pawn.Location) * 1000);

	if(PSPawnEnemyRandom(Pawn).bChatting)
	{
		TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
		PSPawnEnemyRandom(Pawn).bChatting = false;
	}

	bCheckDeadComrade = false;
	TimeSinceTargetLost = 0.0; // Tick() function in Check state is sometimes executed before Begin, so this is a work around
	LastKnownLocation = NoiseSource;
	GotoState('Check');
}

// If the player is so close perform melee attack
simulated function DoMeleeAttack()
{
	// Stop firing
	ResetFiring();

	// Play the animation
	switch(PSPawn(Pawn).CurrentWeapon)
	{
	case(PSPawn(Pawn).EWeapon.WEAPON_Rifle):
		PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Melee_Rifle);
		break;
	case(PSPawn(Pawn).EWeapon.WEAPON_Pistol):
		PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Melee_Pistol);
		break;
	}	
}

// Returns true if is the enemy closer to the last known position of the player which had him targeted
function bool ShouldCheck()
{   
	local PSPawnEnemyRandom currentPawn;
	local float currentDistance;
	local float myDistance;

	// Get the local pawn distance to the player so it can be compared
	myDistance = VSize(LastKnownLocation - PSPawnEnemyRandom(Pawn).Location);

	foreach WorldInfo.AllPawns(class'PSPawnEnemyRandom', currentPawn)
	{
		currentDistance = VSize(LastKnownLocation - currentPawn.Location);

		if( (PSAIControllerBase(currentPawn.Controller).Target != none) && // Candidate pawn has player targeted
			(currentDistance < myDistance) && // Is closer than the local enemy
			(currentPawn != self.Pawn) )  // Not the local enemy
		{
			// The candidate is closest, he should check
			return false;
		}
	}

	// None is closest than local enemy, so he must check
	return true;
}

// Enemy sees the player
// Takes into account line of sight, player invisibility and glass materials
function bool PlayerIsSeen()
{
	local Vector HitLocation;
	local Vector HitNormal;
	local TraceHitInfo HitInfo;
	local PSPawnDidrik PotentialTarget;
	local Actor HitActor;
	local Vector EnemyEyesLocation, PlayerEyesLocation;
	local Rotator EnemyEyesRotation, PlayerEyesRotation;
	local float cosang, angle;

	PotentialTarget = PSPawnDidrik(GetALocalPlayerController().Pawn);

	Pawn.GetActorEyesViewPoint(EnemyEyesLocation, EnemyEyesRotation);
	PotentialTarget.GetActorEyesViewPoint(PlayerEyesLocation, PlayerEyesRotation);

	if(CanSee(PotentialTarget) && 
		!ObstaclesInBetween(EnemyEyesLocation, PlayerEyesLocation) && 
		!PotentialTarget.IsInvisible() &&
		(VSize(Pawn.Location - PotentialTarget.Location) < PSPawnEnemyRandom(Pawn).MaxSightDistance) )
	{
		// Reduce the peripheral version when the player is covered
		if( (PotentialTarget.CurrentPosture == PotentialTarget.EPosture.POSTURE_Covered_Stand) ||
			(PotentialTarget.CurrentPosture == PotentialTarget.EPosture.POSTURE_Covered_Crouch) )
		{
			cosang = NoZDot(Vector(Rotation), PotentialTarget.Location - Pawn.Location);
			angle = Acos(cosang);
			angle = angle * 180/ PI;

			if(angle > 15.0)
			{
				return false;
			}
		}
		// Define the peripheral version for default behavior, becase UDKs CanSee doesn't work as expected...
		else {
			cosang = NoZDot(Vector(Rotation), PotentialTarget.Location - Pawn.Location);
			angle = Acos(cosang);
			angle = angle * 180/ PI;

			if(angle > 75.0)
			{
				return false;
			}
		}

	    return true;
	}
	else if(!PotentialTarget.IsInvisible() &&
		( (Vector(Pawn.Rotation) dot (PotentialTarget.Location - Pawn.Location)) > 0) && 
		(VSize(Pawn.Location - PotentialTarget.Location) < PSPawnEnemyRandom(Pawn).MaxSightDistance))
	{
		foreach Pawn.TraceActors(class'Actor', HitActor, HitLocation, HitNormal, EnemyEyesLocation, PlayerEyesLocation, vect(1,1,1), HitInfo, TRACEFLAG_Blocking)
		{
			if(HitInfo.HitComponent != None)
			{
				if( (MeshComponent(HitInfo.HitComponent) != none) && MeshComponent(HitInfo.HitComponent).GetMaterial(0).Name != 'glass_01' )
				{		
					// Avoid the last hit in the player skeletal mesh
					if(SkeletalMeshComponent(HitInfo.HitComponent) == none)
					{
						// At least 1 material in between is not transparent (!= glass) --> Player is not seen
						return false;
					}
				}   
			}
		}

		if( ((HitInfo.HitComponent) != none) &&
			( (SkeletalMeshComponent(HitInfo.HitComponent) != none) ||
			((MeshComponent(HitInfo.HitComponent) != none) && MeshComponent(HitInfo.HitComponent).GetMaterial(0).Name == 'glass_01') ) )
		{
			// All materials in between are transparent (== glass) or no obstacles in between --> Player is seen
			return true;
		}		
	}

	// Invisible or behind --> Player is not seen
	return false;
}


function bool ObstaclesInBetween(Vector src, Vector dst)
{
	local Vector HitLocation;
	local Vector HitNormal;
	local TraceHitInfo HitInfo;

	if(Trace(HitLocation, HitNormal, dst, src, true, vect(1,1,1), HitInfo, TRACEFLAG_Blocking) != none)
	{
		// Skip when colliding with Didrik mesh
		if((HitInfo.HitComponent != none) && SkeletalMeshComponent(HitInfo.HitComponent) != none) {	return false;	}
		else {	return true;	}
	}
	else {	return false;	}
}


// Returns if the actor is in fire range according to distance variables of the enemy
function bool InFireRange(Actor act)
{
	local PSPawnEnemyRandom P;
	local float distance;

	P = PSPawnEnemyRandom(Pawn);
	distance = VSize(GetALocalPlayerController().Pawn.Location - act.Location);

	return( (distance > P.MinDistanceToPlayer) && // Not too close
			(distance < P.MaxDistanceToPlayer));  // Not too far
}


// Returns if the player is in direct line of sight (with no obstacles) and close enough to start firing from behind
function bool CanAttack()
{
	local PSPawnDidrik P;
	
	P = PSPawnDidrik(GetALocalPlayerController().Pawn);

	return (CanSee(P) && // No obstacles
			InFireRange(Pawn)); // Close enough
}


// Returns if the enemy wants to look for a cover or prefers to evade the player
function bool WantToCover()
{
	return (PSPawnEnemyRandom(Pawn).CoverProb > RandRange(0.0,1.0));
}


function bool FindNavMeshPath(bool DestinationIsNode)
{
	NavigationHandle.PathConstraintList = none;
	NavigationHandle.PathGoalList = none;

	if(DestinationIsNode)
	{
		class'NavMeshPath_Toward'.static.TowardGoal(NavigationHandle, NextNode);
		class'NavMeshGoal_At'.static.AtActor(NavigationHandle, NextNode);
	}
	else
	{
		class'NavMeshPath_Toward'.static.TowardPoint(NavigationHandle, LastKnownLocation);
		class'NavMeshGoal_At'.static.AtLocation(NavigationHandle, LastKnownLocation);
	}

	return NavigationHandle.FindPath();	
}


// Returns a path node when evading
function PSNavigationPoint FindPathNode()
{
	local array<PSPathNode> candidateNodes;
	local PSPathNode tmpNode;
	local int candidatesNumber;

	candidatesNumber = 0;

	foreach WorldInfo.AllNavigationPoints(class'PSPathNode', tmpNode)
	{
		if(InFireRange(tmpNode) && // Path node is close and far enough 
			(!(tmpNode.bAlreadyOccupied)) &&  // Not already a goal for any other enemy
			!ObstaclesInBetween(tmpNode.Location, Target.Location) && // No obstacles in between
			( ( ( (Normal(Vector(Target.Rotation)) dot Normal(Pawn.Location - Target.Location) ) < 0) &&   // Enemy is behind the player
				( (Normal(Vector(Target.Rotation)) dot Normal(tmpNode.Location - Target.Location) ) < 0) ) || // So path node must also be
				( ( (Normal(Vector(Target.Rotation)) dot Normal(Pawn.Location - Target.Location) ) > 0) &&   // Enemy is in front of the player
				( (Normal(Vector(Target.Rotation)) dot Normal(tmpNode.Location - Target.Location) ) > 0) ) ) ) // So path node must also be
		{
			candidateNodes.AddItem(tmpNode);
			candidatesNumber++;
			
			if(candidatesNumber >= MaxNodeCandidates)
			{
				break;
			}
		}	
	}

	// If no node is found, then be less restrictive
	if(candidateNodes.Length == 0)
	{
		foreach WorldInfo.AllNavigationPoints(class'PSPathNode', tmpNode)
		{
			if(InFireRange(tmpNode) && // Path node is close and far enough 
				(!(tmpNode.bAlreadyOccupied)) &&  // Not already a goal for any other enemy
				!ObstaclesInBetween(tmpNode.Location, Target.Location) ) // No obstacles in between				
			{
				candidateNodes.AddItem(tmpNode);
				candidatesNumber++;
			
				if(candidatesNumber >= MaxNodeCandidates)
				{
					break;
				}
			}	
		}

		// If no node is found yet, then be even less restrictive
		if(candidateNodes.Length == 0)
		{
			foreach WorldInfo.AllNavigationPoints(class'PSPathNode', tmpNode)
			{
				if( (VSize(tmpNode.Location - Target.Location) < PSPawnEnemyRandom(Pawn).MaxNodeDistance) && // Node distance is limited
					(!(tmpNode.bAlreadyOccupied)) ) // Not already a goal for any other enemy
				{
					candidateNodes.AddItem(tmpNode);
					candidatesNumber++;
			
					if(candidatesNumber >= MaxNodeCandidates)
					{
						break;
					}
				}	
			}

			// If no node is found yet, then return a random node (infinite loop must be avoided!!)
			if(candidateNodes.Length == 0)
			{
				return PSPathNode(FindRandomDest());		
			}
		}
	}

	tmpNode = candidateNodes[Rand(candidateNodes.length)];
	return tmpNode;	
}


// Returns a cover node when trying to take cover
function PSNavigationPoint FindCoverNode()
{
	local array<PSCoverNode> candidateNodes;
	local PSCoverNode tmpNode;
	local int candidatesNumber;

	candidatesNumber = 0;

	foreach WorldInfo.AllNavigationPoints(class'PSCoverNode', tmpNode)
	{
		if(InFireRange(tmpNode) && // Cover node is close and far enough 
			(!(tmpNode.bAlreadyOccupied)) &&  // Not already a goal for any other enemy
			( ((Normal(Vector(Target.Rotation)) dot Normal(Pawn.Location - Target.Location) < 0) &&   // Enemy is behind the player
				(Normal(Vector(Target.Rotation)) dot Normal(tmpNode.Location - Target.Location) < 0) && // So cover node must also be
				(Normal(Vector(Target.Rotation)) dot Normal(Vector(tmpNode.Rotation)) < 0)) || // Cover node must really protect him
			  ((Normal(Vector(Target.Rotation)) dot Normal(Pawn.Location - Target.Location) > 0) &&   // Enemy is in front of the player
				(Normal(Vector(Target.Rotation)) dot Normal(tmpNode.Location - Target.Location) > 0) && // So cover node must also be
				(Normal(Vector(Target.Rotation)) dot Normal(Vector(tmpNode.Rotation)) > 0)  )) ) // Cover node must really protect him
		{
			candidateNodes.AddItem(tmpNode);
			candidatesNumber++;
			
			if(candidatesNumber >= MaxNodeCandidates)
			{
				break;
			}
		}	
	}

	// If no node is found, then be less restrictive
	if(candidateNodes.Length == 0)
	{
		foreach WorldInfo.AllNavigationPoints(class'PSCoverNode', tmpNode)
		{
			if(InFireRange(tmpNode) && // Cover node is close and far enough 
				(!(tmpNode.bAlreadyOccupied)) &&  // Not already a goal for any other enemy
				( (Normal(tmpNode.Location - Target.Location) dot Normal(Vector(tmpNode.Rotation)) > 0) ) ) // The cover node must really protect him
			{
				candidateNodes.AddItem(tmpNode);
				candidatesNumber++;
			
				if(candidatesNumber >= MaxNodeCandidates)
				{
					break;
				}
			}	
		}

		// If no node is found yet, then be even less restrictive
		if(candidateNodes.Length == 0)
		{
			foreach WorldInfo.AllNavigationPoints(class'PSCoverNode', tmpNode)
			{
				if( (VSize(tmpNode.Location - Target.Location) < PSPawnEnemyRandom(Pawn).MaxNodeDistance) && // Node distance is limited
					(!(tmpNode.bAlreadyOccupied)) &&  // Not already a goal for any other enemy
					( (Normal(tmpNode.Location - Target.Location) dot Normal(Vector(tmpNode.Rotation)) > 0) ) ) // The cover node must really protect him
				{
					candidateNodes.AddItem(tmpNode);
					candidatesNumber++;
			
					if(candidatesNumber >= MaxNodeCandidates)
					{
						break;
					}
				}	
			}

			// If no node is found yet, then return a none so the enemy goes to 'Evade' state
			if(candidateNodes.Length == 0)
			{
				return none;		
			}
		}
	}

	tmpNode = candidateNodes[Rand(candidateNodes.length)];
	return tmpNode;
}


function Rotator GetAdjustedAimFor(Weapon W, vector StartFireLoc)
{
	local Rotator aim;
	
	aim = Rotator(GetFocalPoint() - StartFireLoc);
	//aim.Pitch = NormalizeRotAxis(Pawn.GetBaseAimRotation().Pitch);
	//`log(aim.Pitch);

	// Reduce precision
	aim.Pitch += FFloor(RandRange(0, 3.0) * DegToUnrRot);
	aim.Yaw += FFloor(RandRange(0, 3.0)  * DegToUnrRot);

	return aim;
}

function Fire()
{
	local float BurstLength; // How long is the fire burst
	
	// Make sure that the bot is aiming at the player when firing
	Focus = Target;
	SetFocalPoint(Target.Location);
	FireWeaponAt(Target);

	Pawn.StartFire(0);

	if(PSWeapon(Pawn.Weapon).HasMagAmmo())
	{
		PSPawn(Pawn).PlayRecoil(PSPawn(Pawn).CurrentWeapon);
	}

	bFiring = true;
	BurstLength = RandRange(0.25, 1.5);
	SetTimer(BurstLength, false,'ResetFiring');
}


// Stop firing and wait a little according to weapon/bot fire rate
function ResetFiring()
{
	local float FireRate; // How much time between fire bursts

	Pawn.StopFire(0);
	PSPawn(Pawn).StopRecoil();
	bFiring = false;

	bWaitingToFire = true;
	FireRate = RandRange(1.5, 3.5);
	SetTimer(FireRate, false, 'ResetWaitingToFire');
}

function Reload()
{
	bReloading = true;
	SetTimer(2.0, false, 'ResetReloading');

	// Play reloading animation
	switch(PSPawn(Pawn).CurrentWeapon)
	{
	case(PSPawn(Pawn).EWeapon.WEAPON_Rifle):
		PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Reload_Rifle);
		break;
	case(PSPawn(Pawn).EWeapon.WEAPON_Pistol):
		PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Reload_Pistol);
		break;
	}
	
	// Reset all timers so can fire as soon as the gun is reloaded
	ClearTimer('ResetFiring');
	ClearTimer('ResetWaitingToFire');
	bFiring = false;
	bWaitingToFire = false;
}


// Wait complete
function ResetWaitingToFire()
{
	bWaitingToFire = false;
}

// Reload complete
function ResetReloading()
{
	PSWeapon(Pawn.Weapon).MagAmmo = PSWeapon(Pawn.Weapon).MagMaxAmmo;
	bReloading = false;
}


// If in AI debug mode, prints AI state
function PrintAIState()
{
	if(AI_DEBUG_ENABLED)    
	{
		if(Target != none)  `log(self @ PSPawnEnemyRandom(Pawn).Profile @ GetStateName() $". Target:" @ Target @ "at" @ VSize(Pawn.Location - Target.Location) @ Focus @ FocalPosition.Position);
		else                `log(self @ PSPawnEnemyRandom(Pawn).Profile @ GetStateName() $"." @ Focus @ FocalPosition.Position);
	}
}

event SeePlayer(Pawn Seen)
{
	if(PSPawnDidrik(Seen).IsInvisible())
	{
		return;
	}
}

// Returns true if he sees a dead comrade
function bool SeeDeadComrade()
{
	local PSPawnEnemyRandom currentPawn;
	local PSAIControllerBase currentController;

	foreach WorldInfo.AllPawns(class'PSPawnEnemyRandom', currentPawn)
	{
		currentController = PSAIControllerBase(currentPawn.Controller);	

		if((currentPawn != Pawn) &&                                                     // Not the own pawn
			currentController.IsInState('Dying') &&                                     // Pawn is dead
			!(currentPawn.bJustHeardNoise) &&                                             // Didn't hear any sound before
			!(currentPawn.bAlreadyPrayed) &&                                            // Seen first time
			CanSee(currentPawn) &&                                                      // Can be seen
			!ObstaclesInBetween(Pawn.Location, currentPawn.Location) &&                 // No obstacles in between (previous condition is kind of buggy)
			(VSize(Pawn.Location - currentPawn.Location) < PSPawnEnemyRandom(Pawn).MaxSightDistance))      // Close enough
		{
			LastKnownLocation = currentPawn.Location;
			currentPawn.bAlreadyPrayed = true; 
			bCheckDeadComrade = true;
			return true;
		}
	}

	return false;
}

// Returns true if he sees a comrade fighting
function bool SeeFight()
{
	local PSPawnEnemyRandom currentPawn;
	local PSAIControllerBase currentController;

	foreach WorldInfo.AllPawns(class'PSPawnEnemyRandom', currentPawn)
	{
		currentController = PSAIControllerBase(currentPawn.Controller);	

		if((currentPawn != Pawn) &&                                                     // Not the own pawn
			(currentController.IsInState('Evade') ||                                    // Pawn is in Evade
			currentController.IsInState('TakeCover') ||									//   or TakeCover
			currentController.IsInState('Cover') ||										//   or Cover
			currentController.IsInState('Attack') ) &&									//   or Attack state
			CanSee(currentPawn) &&                                                      // Can be seen
			!ObstaclesInBetween(Pawn.Location, currentPawn.Location) &&                 // No obstacles in between (previous condition is kind of buggy)
			(VSize(Pawn.Location - currentPawn.Location) < PSPawnEnemyRandom(Pawn).MaxSightDistance))      // Close enough
		{
			return true;
		}
	}

	return false;
}


function ClearCanPlayAudio()
{
	bCanPlayAudio = true;
}

// Standard idle state, doing nothing
auto state Idle
{
	event Tick(float DeltaTime)
	{
		// Check if new patrolling nodes have been set
		if(PatrolNodes.Length > 0)
		{
			GotoState('Patrol');
		}

		if(PlayerIsSeen() || PSPawnEnemyRandom(Pawn).bBeingAttacked || SeeFight())
		{
			if(PSPawnEnemyRandom(Pawn).bChatting)
			{
				TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
				PSPawnEnemyRandom(Pawn).bChatting = false;
			}
	
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}			
		}
		else if(SeeDeadComrade())
		{
			GotoState('GoToCheck');
		}

		// If doesn't change its state and not chatting, check if can play sound
		if(bCanPlayAudio && !PSPawnEnemyRandom(Pawn).bChatting)
		{
			PSPawnEnemyRandom(Pawn).PlayPeaceAudio();
			bCanPlayAudio = false;
			SetTimer(RandRange(15.0, 30.0), false, 'ClearCanPlayAudio');
		}
	}

Begin:
	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Walking;
	if(PatrolNodes.Length > 0)
	{
		GotoState('Patrol');
	}
	else 
	{
		// Reset values
		Target = none;
		PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Idle);
		Focus = none;
		SetRotation(SpawnRotation);
		SetFocalPoint(SpawnFocalPoint);
	}
	
}


// Walk from pathnode to pathnode in a patrolling route
state Patrol
{
	event Tick(float DeltaTime)
	{
		if(PlayerIsSeen() || PSPawnEnemyRandom(Pawn).bBeingAttacked || SeeFight())
		{
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}			
		}
		else if(SeeDeadComrade())
		{
			GotoState('GoToCheck');
		}

		// If doesn't change its state, check if can play sound
		if(bCanPlayAudio)
		{
			PSPawnEnemyRandom(Pawn).PlayPeaceAudio();
			bCanPlayAudio = false;
			SetTimer(RandRange(15.0, 30.0), false, 'ClearCanPlayAudio');
		}
	}
	
Begin:
	// Reset values
	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Walking;
	Target = none;
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Walking);

	NextNode = PatrolNodes[NextPatrolNodeIndex];

	if( (NextPatrolNodeIndex == 0) ||
		(NextPatrolNodeIndex == (PatrolNodes.Length/2) + 1) )
	{
		Sleep(5.0);
	}

	NextPatrolNodeIndex++;	

	if(NextPatrolNodeIndex == PatrolNodes.Length)
	{
		NextPatrolNodeIndex = 0;
	}

	if(NextNode != none) 
	{
		PSNavigationPoint(NextNode).bAlreadyOccupied = true;

		if(CurrentNode != none) 
		{
			PSNavigationPoint(CurrentNode).bAlreadyOccupied = false;
		}		
	}

	if(FindNavMeshPath(true))
	{
		NavigationHandle.SetFinalDestination(NextNode.Location);

		while(!Pawn.ReachedDestination(NextNode))
		{
			// Final location is reachable, so go straight
			if(NavigationHandle.ActorReachable(NextNode))
			{
				MoveToward(NextNode);
			}
			// Final location is not reachable, so find a way to get it
			else 
			{		
				if(NavigationHandle.GetNextMoveLocation(TempDest, Pawn.GetCollisionRadius()))
				{
					// Avoid infinite loop due to path finding problems
					if(PreviousLocation == Pawn.Location)
					{
						break;
					}

					PreviousLocation = Pawn.Location;

					MoveTo(TempDest);
				}
			}
		}
	}
	else
	{
		if(NextNode != none) 
		{
			PSNavigationPoint(NextNode).bAlreadyOccupied = false;
		}
		
		Sleep(0.f);
		goto 'Begin';
	}

	Sleep(0.f);
	goto 'Begin';
}


// Keep moving from location to location while firing the player
state Evade
{
	event Tick(float DeltaTime)
	{
		if(Target == none)
		{
			Target = PSPawnDidrik(GetALocalPlayerController().Pawn);
		}
		
		Pawn.GetActorEyesViewPoint(TraceStartLoc, TraceStartRot);
		Target.GetActorEyesViewPoint(TraceEndLoc, TraceEndRot);

		if(Target.bIsDeath)
		{
			GotoState('Stopped');
		}
		else if(VSize(Target.Location - Pawn.Location) <= PSPawnEnemyRandom(Pawn).MeleeDistance)
		{
			DoMeleeAttack();
		}
		else if (!PSWeapon(Pawn.Weapon).HasMagAmmo() && !bReloading)
		{
			Reload();
		}
		else if( !(Target.isInvisible()) &&
			CanSee(Target) && 
			!ObstaclesInBetween(TraceStartLoc, TraceEndLoc) && 
			!bFiring && 
			!bWaitingToFire &&
			!bReloading)
		{
			Fire();
		}

		if(Target.IsInvisible())
		{
			if(ShouldCheck())
			{
				GotoState('Upset');
			}
			else
			{
				// Save the last target location
				LastKnownLocation = Target.Location;
				GotoState('Check');
			}
		}

		// If doesn't change its state, check if can play sound
		if(bCanPlayAudio)
		{
			PSPawnEnemyRandom(Pawn).PlayWarFightAudio();
			bCanPlayAudio = false;
			SetTimer(RandRange(10.0, 20.0), false, 'ClearCanPlayAudio');
		}
	}

Begin:
	// If playing any animation, stop it
	if(PSPawn(Pawn).FullBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).FullBodyAnimNodeSlot.StopCustomAnim(0.1);
	}
	if(PSPawn(Pawn).TopHalfBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).TopHalfBodyAnimNodeSlot.StopCustomAnim(0.1);
	}

	if(PSPawnEnemyRandom(Pawn).bChatting)
	{
		TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
		PSPawnEnemyRandom(Pawn).bChatting = false;
	}

	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Running;
	Target = PSPawnDidrik(GetALocalPlayerController().Pawn);
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Running);

	NextNode = FindPathNode(); 

	if(NextNode != none) 
	{
		PSNavigationPoint(NextNode).bAlreadyOccupied = true;

		if(CurrentNode != none) 
		{
			PSNavigationPoint(CurrentNode).bAlreadyOccupied = false;
		}		
	}
	// If no proper node was found, then switch to take cover state
	else if (CurrentNode == none)
	{
		Sleep(0.f);
		GotoState('TakeCover');
	}

	if(FindNavMeshPath(true))
	{
		NavigationHandle.SetFinalDestination(NextNode.Location);

		while(!Pawn.ReachedDestination(NextNode))
		{
			// Final location is reachable, so go straight
			if(NavigationHandle.ActorReachable(NextNode))
			{
				MoveToward(NextNode, Target);
			}
			// Final location is not reachable, so find a way to get it
			else 
			{		
				if(NavigationHandle.GetNextMoveLocation(TempDest, Pawn.GetCollisionRadius()))
				{
					// Avoid infinite loop due to path finding problems
					if(PreviousLocation == Pawn.Location)
					{
						break;
					}

					PreviousLocation = Pawn.Location;

					MoveTo(TempDest, PlayerIsSeen() ? Target : none);
				}
				else
				{
					// Avoid infinite loops
					if(NextNode != none) 
					{
						PSNavigationPoint(NextNode).bAlreadyOccupied = false;
					}
					
					if(WantToCover())
					{
						Sleep(0.f);
						goto 'Begin';
					}
					else
					{			
						GotoState('Evade');
					}
				}
			}
		}
	
		// Don't stop moving while being attacked
		if(PSPawnEnemyRandom(Pawn).bBeingAttacked)
		{
			if(WantToCover())
			{
				Sleep(0.f);
				GotoState('TakeCover');
			}
			else
			{		
				Sleep(0.f);
				goto 'Begin';
			}
		}
		// If not being attacked, then stop moving and attack
		else
		{
			Sleep(0.f);
			GotoState('Attack');
		}
	}
	else
	{
		if(NextNode != none) 
		{
			PSNavigationPoint(NextNode).bAlreadyOccupied = false;
		}
		
		Sleep(0.f);
		GotoState('TakeCover');
	}
}


// Search for a valid cover, find a path, and go for it
state TakeCover
{
	event Tick(float DeltaTime)
	{
		if(Target == none)
		{
			Target = PSPawnDidrik(GetALocalPlayerController().Pawn);
		}

		Pawn.GetActorEyesViewPoint(TraceStartLoc, TraceStartRot);
		Target.GetActorEyesViewPoint(TraceEndLoc, TraceEndRot);

		if(Target.bIsDeath)
		{
			GotoState('Stopped');
		}
		else if(VSize(Target.Location - Pawn.Location) <= PSPawnEnemyRandom(Pawn).MeleeDistance)
		{
			DoMeleeAttack();
		}
		else if (!PSWeapon(Pawn.Weapon).HasMagAmmo() && !bReloading)
		{
			Reload();
		}
		else if( !(Target.isInvisible()) &&
			CanSee(Target) && 
			!ObstaclesInBetween(TraceStartLoc, TraceEndLoc) && 
			!bFiring && 
			!bWaitingToFire &&
			!bReloading)
		{
			Fire();
		}

		if(Target.IsInvisible())
		{
			if(ShouldCheck())
			{
				GotoState('Upset');
			}
			else
			{
				// Save the last target location
				LastKnownLocation = Target.Location;
				GotoState('Check');
			}
		}

		// If doesn't change its state, check if can play sound
		if(bCanPlayAudio)
		{
			PSPawnEnemyRandom(Pawn).PlayWarFightAudio();
			bCanPlayAudio = false;
			SetTimer(RandRange(10.0, 25.0), false, 'ClearCanPlayAudio');
		}
	}

Begin:
	// If playing any animation, stop it
	if(PSPawn(Pawn).FullBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).FullBodyAnimNodeSlot.StopCustomAnim(0.1);
	}
	if(PSPawn(Pawn).TopHalfBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).TopHalfBodyAnimNodeSlot.StopCustomAnim(0.1);
	}

	if(PSPawnEnemyRandom(Pawn).bChatting)
	{
		TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
		PSPawnEnemyRandom(Pawn).bChatting = false;
	}

	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Running;
	Target = PSPawnDidrik(GetALocalPlayerController().Pawn);
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Running);

	NextNode = FindCoverNode(); 

	if(NextNode != none) 
	{
		PSNavigationPoint(NextNode).bAlreadyOccupied = true;

		if(CurrentNode != none) 
		{
			PSNavigationPoint(CurrentNode).bAlreadyOccupied = false;
		}		
	}
	// If no proper cover node was found, then switch to evade state
	else if (CurrentNode == none)
	{
		Sleep(0.f);
		GotoState('Evade');
	}

	if(FindNavMeshPath(true))
	{
		NavigationHandle.SetFinalDestination(NextNode.Location);

		while(!Pawn.ReachedDestination(NextNode))
		{
			// Final location is reachable, so go straight
			if(NavigationHandle.ActorReachable(NextNode))
			{
				MoveToward(NextNode, Target);
			}
			// Final location is not reachable, so find a way to get it
			else 
			{		
				if(NavigationHandle.GetNextMoveLocation(TempDest, Pawn.GetCollisionRadius()))
				{
					// Avoid infinite loop due to path finding problems
					if(PreviousLocation == Pawn.Location)
					{
						break;
					}

					PreviousLocation = Pawn.Location;

					MoveTo(TempDest, PlayerIsSeen() ? Target : none);
				}
				else
				{
					// Avoid infinite loops
					if(NextNode != none) 
					{
						PSNavigationPoint(NextNode).bAlreadyOccupied = false;
					}
					
					if(WantToCover())
					{
						Sleep(0.f);
						goto 'Begin';
					}
					else
					{		
						Sleep(0.f);
						GotoState('Evade');
					}
				}
			}
		}

		// Destination reached
		if(Pawn.ReachedDestination(NextNode))
		{
			Sleep(0.f);
			GotoState('Cover');
		}
		else
		{
			Sleep(0.f);
			goto 'Begin';
		}
	}
	else
	{
		if(NextNode != none) 
		{
			PSNavigationPoint(NextNode).bAlreadyOccupied = false;
		}

		Sleep(0.f);
		GotoState('Evade');
	}	
}


// Remain in cover for a while
state Cover
{
	event Tick(float DeltaTime)
	{
		if(Target.bIsDeath)
		{
			GotoState('Stopped');
		}

		TimeSinceTookCover += DeltaTime;

		if(Target.IsInvisible())
		{
			if(ShouldCheck())
			{
				GotoState('Upset');
			}
			else
			{
				// Save the last target location
				LastKnownLocation = Target.Location;
				GotoState('Check');
			}
		}
		else if ( (TimeSinceTookCover >= PSPawnEnemyRandom(Pawn).CoverTime) ||
			PSPawnEnemyRandom(Pawn).bBeingAttacked ||
			!ObstaclesInBetween(Target.Location, PSPawnEnemyRandom(Pawn).Location) )
		{
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}
		}

		// If doesn't change its state, check if can play sound
		if(bCanPlayAudio)
		{
			PSPawnEnemyRandom(Pawn).PlayWarFightAudio();
			bCanPlayAudio = false;
			SetTimer(RandRange(10.0, 25.0), false, 'ClearCanPlayAudio');
		}
	}

Begin:
	TimeSinceTookCover = 0.0;
	CurrentNode = NextNode;
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Idle);

	// Stop firing if doing it
	ResetFiring();

	if(PSCoverNode(CurrentNode).bLow)
	{
		PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Covered_Crouch;
	}
	else
	{
		PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Covered_Stand;
	}

	Focus = none;
	SetRotation(CurrentNode.Rotation);
	SetFocalPoint(Pawn.Location + Normal(Vector(CurrentNode.Rotation)) * 1000);
}


// Attack the player in case there is no need to evade 
state Attack
{
	event Tick(float DeltaTime)
	{
		if(Target == none)
		{
			Target = PSPawnDidrik(GetALocalPlayerController().Pawn);
		}

		Pawn.GetActorEyesViewPoint(TraceStartLoc, TraceStartRot);
		Target.GetActorEyesViewPoint(TraceEndLoc, TraceEndRot);

		if(Target.bIsDeath)
		{
			GotoState('Stopped');
		}
		else if(VSize(Target.Location - Pawn.Location) <= PSPawnEnemyRandom(Pawn).MeleeDistance)
		{
			DoMeleeAttack();
		}
		else if (!PSWeapon(Pawn.Weapon).HasMagAmmo() && !bReloading)
		{
			Reload();
		}
		else if( !(Target.isInvisible()) &&
			CanSee(Target) && 
			!ObstaclesInBetween(TraceStartLoc, TraceEndLoc) && 
			!bFiring && 
			!bWaitingToFire &&
			!bReloading)
		{
			Fire();
		}

		if(Target.IsInvisible())
		{
			if(ShouldCheck())
			{
				GotoState('Upset');
			}
			else
			{
				// Save the last target location
				LastKnownLocation = Target.Location;
				GotoState('Check');
			}
		}
		else if (PSPawnEnemyRandom(Pawn).bBeingAttacked ||    // Move if player attacks
				!InFireRange(Pawn) ||    // Or if the player is too far or too close     
				!CanSee(Target) || // Player is not in line of sight
				ObstaclesInBetween(Pawn.Location, Target.Location) ) // Something in between
		{
			if(WantToCover())
			{
				GotoState('TakeCover');
			}
			else
			{
				GotoState('Evade');
			}
		}

		// If doesn't change its state, check if can play sound
		if(bCanPlayAudio)
		{
			PSPawnEnemyRandom(Pawn).PlayWarFightAudio();
			bCanPlayAudio = false;
			SetTimer(RandRange(10.0, 20.0), false, 'ClearCanPlayAudio');
		}
	}

Begin:
	// If playing any animation, stop it
	if(PSPawn(Pawn).FullBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).FullBodyAnimNodeSlot.StopCustomAnim(0.1);
	}
	if(PSPawn(Pawn).TopHalfBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).TopHalfBodyAnimNodeSlot.StopCustomAnim(0.1);
	}

	if(PSPawnEnemyRandom(Pawn).bChatting)
	{
		TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
		PSPawnEnemyRandom(Pawn).bChatting = false;
	}

	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Running;
	Target = PSPawnDidrik(GetALocalPlayerController().Pawn);
	Focus = Target;
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Idle);
}

// When the player vanishes
state Upset
{
	event Tick(float DeltaTime)
	{
		if(PlayerIsSeen() || PSPawnEnemyRandom(Pawn).bBeingAttacked)
		{
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}			
		}
		else 
		{
			TimeSinceUpset += DeltaTime;

			if(TimeSinceUpset >= PSPawnEnemyRandom(Pawn).UpsetTime)
			{
				if(ShouldCheck())
				{
					GotoState('GoToCheck');
				}
				else
				{
					// If the enemy is a patroller, then go to the next patrolling node
					if(PatrolNodes.Length > 0)
					{
						GotoState('Patrol');
					}
					// If not a patroller, go back to spawn node
					else
					{
						GotoState('BackToStart');
					}
				}
			}

			// If doesn't change its state, check if can play sound
			if(bCanPlayAudio)
			{
				PSPawnEnemyRandom(Pawn).PlayWarLostAudio();
				bCanPlayAudio = false;
				SetTimer(PSPawnEnemyRandom(Pawn).UpsetTime + 1.0, false, 'ClearCanPlayAudio');
			}
		}	
	}

Begin:
	// Stop firing if doing it
	ResetFiring();

	// If playing any animation, stop it
	if(PSPawn(Pawn).FullBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).FullBodyAnimNodeSlot.StopCustomAnim(0.1);
	}
	if(PSPawn(Pawn).TopHalfBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).TopHalfBodyAnimNodeSlot.StopCustomAnim(0.1);
	}

	if(PSPawnEnemyRandom(Pawn).bChatting)
	{
		TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
		PSPawnEnemyRandom(Pawn).bChatting = false;
	}

	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Checking;

	// Stop moving
	StopLatentExecution();
	Pawn.Acceleration = vect(0,0,0);

	// Play upset animation with a certain probability, thus avoiding all enemies doing the same animation 
	if(RandRange(0.0, 1.0) > 0.9)
	{
		// Wait some time to play the animation, thus avoiding all playing it at the same time
		Sleep(RandRange(0.0, 5.0));

		switch(PSPawn(Pawn).CurrentWeapon)
		{
		case(PSPawn(Pawn).EWeapon.WEAPON_Rifle):
			PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Look_Around_Fast_Rifle);
			break;
		case(PSPawn(Pawn).EWeapon.WEAPON_Pistol):
			PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Look_Around_Fast_Pistol);
			break;
		}
	}
	
	// Save the last target location
	LastKnownLocation = Target.Location;

	Focus = none;
	SetRotation(Rotation);
	SetFocalPoint(LastKnownLocation);
	
	TimeSinceUpset = 0.0;
}



// Go to the last known position of the player and take a look
state GoToCheck
{
	event Tick(float DeltaTime)
	{
		if(PlayerIsSeen() || PSPawnEnemyRandom(Pawn).bBeingAttacked)
		{
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}			
		}
	}

Begin:
	// Stop firing if doing it
	ResetFiring();

	// If playing any animation, stop it
	if(PSPawn(Pawn).FullBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).FullBodyAnimNodeSlot.StopCustomAnim(0.1);
	}
	if(PSPawn(Pawn).TopHalfBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).TopHalfBodyAnimNodeSlot.StopCustomAnim(0.1);
	}

	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Checking;
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Walking);

	// As the enemy is leaving the current node or discarding next node, let others to consider it
	if(CurrentNode != none)
	{
		PSNavigationPoint(CurrentNode).bAlreadyOccupied = false;
	}
	if(NextNode != none)
	{
		PSNavigationPoint(NextNode).bAlreadyOccupied = false;
	}

	if(FindNavMeshPath(false))
	{
		NavigationHandle.SetFinalDestination(LastKnownLocation);

		while(!Pawn.ReachedPoint(LastKnownLocation, none))
		{
			// Final location is reachable, so go straight
			if(NavigationHandle.PointReachable(LastKnownLocation))
			{
				MoveTo(LastKnownLocation);
			}
			// Final location is not reachable, so find a way to get it
			else 
			{		
				if(NavigationHandle.GetNextMoveLocation(TempDest, Pawn.GetCollisionRadius()))
				{
					// Avoid infinite loop due to path finding problems
					if(PreviousLocation == Pawn.Location)
					{
						break;
					}

					PreviousLocation = Pawn.Location;

					MoveTo(TempDest);
				}
				else
				{
					// Avoid infinite loops
					if(NextNode != none) 
					{
						PSNavigationPoint(NextNode).bAlreadyOccupied = false;
					}
					
					Sleep(0.f);
					GotoState('Check');
				}
			}
		}

		// Destination reached
		Sleep(0.f);
		GotoState('Check');
	}
	else
	{
		Sleep(0.f);
		GotoState('BackToStart');
	}
}


// Check the location where the player disappeared or a dead comrade
state Check
{
	event Tick(float DeltaTime)
	{
		if(PlayerIsSeen() || PSPawnEnemyRandom(Pawn).bBeingAttacked)
		{
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}			
		}
		else if(SeeDeadComrade())
		{
			GotoState('GoToCheck');
		}
		else 
		{
			TimeSinceTargetLost += DeltaTime;

			if(TimeSinceTargetLost >= PSPawnEnemyRandom(Pawn).CheckTime)
			{
				// If the enemy is a patroller, then go to the next patrolling node
				if(PatrolNodes.Length > 0)
				{
					GotoState('Patrol');
				}
				// If not a patroller, go back to spawn node
				else
				{
					GotoState('BackToStart');
				}
			}
		}		
	}

Begin:
	// Stop firing if doing it
	ResetFiring();

	// If playing any animation, stop it
	if(PSPawn(Pawn).FullBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).FullBodyAnimNodeSlot.StopCustomAnim(0.1);
	}
	if(PSPawn(Pawn).TopHalfBodyAnimNodeSlot.GetPlayedAnimation() != '')
	{
		PSPawn(Pawn).TopHalfBodyAnimNodeSlot.StopCustomAnim(0.1);
	}

	if(PSPawnEnemyRandom(Pawn).bChatting)
	{
		TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
		PSPawnEnemyRandom(Pawn).bChatting = false;
	}

	// Play check animation
	switch(PSPawn(Pawn).CurrentWeapon)
	{
	case(PSPawn(Pawn).EWeapon.WEAPON_Rifle):
		if(bCheckDeadComrade)  
		{   
			PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Check_Floor_Rifle);
			bCheckDeadComrade = false;
		}
		else 
		{
			PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Look_Around_Slow_Rifle);
		}
		break;
	case(PSPawn(Pawn).EWeapon.WEAPON_Pistol):
		if(bCheckDeadComrade)  
		{
			PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Check_Floor_Pistol);
			bCheckDeadComrade = false;
		}
		else 
		{
			PSPawn(Pawn).PlayAnim(PSPawn(Pawn).EAnimations.ANIM_Enemy_Look_Around_Slow_Pistol);
		}
		break;
	}

	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Checking;
	TimeSinceTargetLost = 0.0;
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Idle);

	Focus = none;
	SetRotation(Rotation);
	SetFocalPoint(LastKnownLocation);
}


state BackToStart
{
	event Tick(float DeltaTime)
	{
		if(PlayerIsSeen() || PSPawnEnemyRandom(Pawn).bBeingAttacked || SeeFight())
		{
			if(CanAttack())
			{
				GotoState('Attack');
			}
			else
			{
				if(WantToCover())
				{
					GotoState('TakeCover');
				}
				else
				{
					GotoState('Evade');
				}
			}			
		}
		else if(SeeDeadComrade())
		{
			GotoState('GoToCheck');
		}
	}

Begin:
	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Walking;
	Target = none;
	PSPawnEnemyRandom(Pawn).SetMovingSpeed(PSPawnEnemyRandom(Pawn).EMovingSpeed.SPEED_Walking);

	LastKnownLocation = SpawnLocation;

	if(FindNavMeshPath(false))
	{
		NavigationHandle.SetFinalDestination(LastKnownLocation);

		while(!Pawn.ReachedPoint(LastKnownLocation, none))
		{
			// Final location is reachable, so go straight
			if(NavigationHandle.PointReachable(LastKnownLocation))
			{
				MoveTo(LastKnownLocation);
			}
			// Final location is not reachable, so find a way to get it
			else 
			{		
				if(NavigationHandle.GetNextMoveLocation(TempDest, Pawn.GetCollisionRadius()))
				{
					// Avoid infinite loop due to path finding problems
					if(PreviousLocation == Pawn.Location)
					{
						break;
					}

					PreviousLocation = Pawn.Location;

					MoveTo(TempDest);
				}
				else
				{
					// Avoid infinite loops
					if(NextNode != none) 
					{
						PSNavigationPoint(NextNode).bAlreadyOccupied = false;
					}
					
					GotoState('Idle');
				}
			}
		}

		// Destination reached
		GotoState('Idle');
	}
	else
	{
		GotoState('Idle');
	}
}

state Dying
{
	event Tick(float DeltaTime)
	{
		if(PSPawnEnemyRandom(Pawn).bChatting)
		{
			TriggerEventClass(class'PSSeqEvent_StopChatting', self, 0);
			PSPawnEnemyRandom(Pawn).bChatting = false;
		}
	}

Begin:
	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Running;
}

state Stopped
{

Begin:
	PSPawn(Pawn).CurrentPosture = PSPawn(Pawn).EPosture.POSTURE_Running;
	// Stop moving
	StopLatentExecution();
	Pawn.Acceleration = vect(0,0,0);
}

DefaultProperties
{
	AI_DEBUG_ENABLED=false

	bFiring=false
	bWaitingToFire=false
	bReloading=false
	bCanPlayAudio=true
	bCheckDeadComrade=false
	MaxNodeCandidates=5
}
